#ifndef _INCLUDED_RPC_INL_H_
#define _INCLUDED_RPC_INL_H_

#include <type_traits>

#include "rpc.h"
#include "serialize.h"

rpc_message::rpc_message(const std::vector<char>& serialized_str)
{
	static_assert((sizeof(unsigned int) == 4 * sizeof(char)),"INT's size is NOT equal to 4 CHARs");
	rpc_id = *(unsigned int*)&serialized_str[0];
	arg_str_length = serialized_str.size() - sizeof(unsigned int);
	arg_str = &serialized_str[sizeof(rpc_id)];
}
std::vector<char> rpc_message::pack()
{
	//todo
	return std::vector<char>();
}

template<typename Handler>
class function_stub{
public:
	virtual void call(const char* args, int length, Handler handler) = 0;
	virtual ~function_stub(){}
};

//Wait for variadic template support
//Nasty implementation NOW!
//Maybe it's better to use boost PP
template<typename Handler>
class function_stub_impl0:public function_stub<Handler>{
	typedef void (function_t)(Handler);
	function_t fptr_;
public:
	function_stub_impl0(function_t fptr):fptr_(fptr){}
	virtual void call(const char* args, int length, Handler handler){call(handler);}
	void call(Handler handler)
	{
		fptr_(handler);
	}
};
template<typename Handler,typename Arg0>
class function_stub_impl1:public function_stub<Handler>{
	typedef void (*function_t)(Handler,const Arg0&);
	function_t fptr_;
public:
	function_stub_impl1(function_t fptr):fptr_(fptr){}
	virtual void call(const char* args, int length, Handler handler)
	{
		//static_assert(std::is_pod<Arg0>::value,"Arg0 is NOT a POD type");
		Arg0 arg0;
		if(deserialize(&args,&length,&arg0))
			call(handler,arg0);
	}
	void call(Handler handler,const Arg0& arg0)
	{
		fptr_(handler,arg0);
	}
};

template<typename Handler,typename Arg0,typename Arg1>
class function_stub_impl2:public function_stub<Handler>{
	typedef void (function_t)(Handler,Arg0,Arg1);
	function_t fptr_;
public:
	function_stub_impl2(function_t fptr):fptr_(fptr){}
	virtual void call(const char* args, int length, Handler handler)
	{
		//static_assert(std::is_pod<Arg0>::value,"Arg0 is NOT a POD type");
		//static_assert(std::is_pod<Arg1>::value,"Arg1 is NOT a POD type");
		Arg0 arg0;
		Arg1 arg1;
		if(deserialize(&args,&length,&arg0,&arg1))
			call(handler,arg0,arg1);
	}
	void call(Handler handler,const Arg0& arg0,const Arg1& arg1)
	{
		fptr_(handler,arg0,arg1);
	}
};
template<typename Handler,typename Arg0,typename Arg1,typename Arg2>
class function_stub_impl3:public function_stub<Handler>{
	typedef void (function_t)(Handler,Arg0,Arg1,Arg2);
	function_t fptr_;
public:
	function_stub_impl3(function_t fptr):fptr_(fptr){}
	virtual void call(const char* args, int length, Handler handler)
	{
		//static_assert(std::is_pod<Arg0>::value,"Arg0 is NOT a POD type");
		//static_assert(std::is_pod<Arg1>::value,"Arg1 is NOT a POD type");
		//static_assert(std::is_pod<Arg2>::value,"Arg2 is NOT a POD type");
		Arg0 arg0;
		Arg1 arg1;
		Arg2 arg2;
		deserialize(&args,&length,&arg0,&arg1,&arg2);
		call(handler,arg0,arg1,arg2);
	}
	void call(Handler handler,const Arg0& arg0,const Arg1& arg1,const Arg2& arg2)
	{
		fptr_(arg0,arg1,arg2);
	}
};
/*
//
template<typename Handler,typename... Arg>
class function_stub_impl:public function_stub<Handler>{
	typedef void (function_t)(Arg arg...);
	function_t fptr_;
public:
	function_stub_impl(function_t fptr):fptr_(fptr){}
	virtual void call(const char* args, int length, Handler handler);
	void call(Arg arg...)
	{
		fptr_(arg...);
	}

};

template<typename Handler, typename ...Arg>
void function_stub_impl::call(const char* args, int length, Handler handler)
{
	int n = sizeof...(Arg);
}
*/

#endif